package com.sc.nft.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.MallUserWithdrawalsRecordDao;
import com.sc.nft.dao.StaticDataDao;
import com.sc.nft.dao.WxMiniUserInfoDao;
import com.sc.nft.entity.SysMember;
import com.sc.nft.entity.WxMiniUserInfo;
import com.sc.nft.entity.minimall.MallUserWallet;
import com.sc.nft.entity.minimall.MallUserWithdrawalsRecord;
import com.sc.nft.entity.vo.WxMiniUserWithdrawalsVO;
import com.sc.nft.entity.vo.mall.MallUserWithdrawalsRecordAdminPage;
import com.sc.nft.enums.MallUserWalletDetailTypeEnum;
import com.sc.nft.enums.MallWithdrawType;
import com.sc.nft.enums.WithdrawalsStatusEnum;
import com.sc.nft.enums.WithdrawalsTradeStatusEnum;
import com.sc.nft.enums.wallet.MallUserWalletStatus;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.WxMiniPayClient;
import com.sc.nft.req.wxPay.BatchTransferReq;
import com.sc.nft.service.MallUserWalletService;
import com.sc.nft.service.MallUserWithdrawalsRecordService;
import com.sc.nft.sup.Result;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.util.OrderNoUtil;
import com.sc.nft.vo.wxPay.InitiateBatchTransferResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 用户提现记录表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-05-20
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallUserWithdrawalsRecordServiceImpl implements MallUserWithdrawalsRecordService {

    private final MallUserWithdrawalsRecordDao mallUserWithdrawalsRecordDao;
    private final StaticDataDao staticDataDao;
    private final MallUserWalletService mallUserWalletService;
    private final WxMiniPayClient wxMiniPayClient;
    private final WxMiniUserInfoDao wxMiniUserInfoDao;

    /**
     * 用户申请提现
     *
     * @param amount
     * @param wxMiniUserInfo
     * @param withdrawType
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userApplicationForWithdrawal(BigDecimal amount, WxMiniUserInfo wxMiniUserInfo, MallWithdrawType withdrawType, String actualName) throws GlobalException {

        // 获取提现最低金额门槛
        BigDecimal minimumAmount = BigDecimalUtils.p(staticDataDao.getByType("minimum_withdrawal_threshold").getValue());

        // 判断提现金额是否符合起提门槛
        if (minimumAmount.compareTo(amount) > 0) {
            log.info("可提现金额少于最低门槛金额,用户ID:{}", wxMiniUserInfo.getId());
            throw new GlobalException("提现金额少于最低门槛金额");
        }
        // 获取钱包
        MallUserWallet mallUserWallet = mallUserWalletService.getMallUserWallet(wxMiniUserInfo.getId());
        if (MallUserWalletStatus.FORBIDDEN == mallUserWallet.getStatus()) {
            throw new GlobalException("账户已被冻结,无法提现");
        }
        Boolean compare = BigDecimalUtils.compareTo(mallUserWallet.getBalance(), amount);
        if (!compare) {
            // 提现金额大于可以提现金额
            log.info("用户申请提现异常:提现金额大于可以提现金额,用户ID:{}", wxMiniUserInfo.getId());
            throw new GlobalException("提现金额大于可以提现金额");
        }

        // 将 钱包的可用金额 转移到 提现锁定金额
        Long walletDetailId = mallUserWalletService.addWithdrawingAmount(mallUserWallet, amount, MallUserWalletDetailTypeEnum.WITHDRAW);
        // 添加提现的记录
        String outTradeNo = OrderNoUtil.getOrderNo("WR");
        MallUserWithdrawalsRecord mallUserWithdrawalsRecord = new MallUserWithdrawalsRecord();
        mallUserWithdrawalsRecord.setMiniUserId(wxMiniUserInfo.getId());
        mallUserWithdrawalsRecord.setWithdrawType(MallWithdrawType.WX_WITHDRAW);
        mallUserWithdrawalsRecord.setWalletDetailId(walletDetailId);
        mallUserWithdrawalsRecord.setActualName(actualName);
        mallUserWithdrawalsRecord.setUserTel(wxMiniUserInfo.getUserTel());
        mallUserWithdrawalsRecord.setAmount(amount);
        mallUserWithdrawalsRecord.setCharge(BigDecimal.ZERO);
        mallUserWithdrawalsRecord.setRealAmount(amount);
        mallUserWithdrawalsRecord.setOutTradeNo(outTradeNo);
        mallUserWithdrawalsRecord.setWithdrawalsStatus(WithdrawalsStatusEnum.TO_BE_WITHDRAWN);
        mallUserWithdrawalsRecord.setTradeStatus(WithdrawalsTradeStatusEnum.TO_BE_WITHDRAWN);
        mallUserWithdrawalsRecord.insert();
    }

    /**
     * 获取提现记录
     *
     * @param startTime
     * @param endTime
     * @param userTel
     * @param withdrawalsStatus
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Page<MallUserWithdrawalsRecordAdminPage> getAdminPage(Date startTime, Date endTime, String userTel, WithdrawalsStatusEnum withdrawalsStatus, Integer pageNo, Integer pageSize) {
        return mallUserWithdrawalsRecordDao.getAdminPage(startTime, endTime, userTel, withdrawalsStatus, pageNo, pageSize);
    }

    /**
     * 用户提现记录
     *
     * @param wxMiniUserId
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Page<WxMiniUserWithdrawalsVO> getUserWithdrawalsRecord(Long wxMiniUserId, Integer pageNo, Integer pageSize) {
        return mallUserWithdrawalsRecordDao.getUserWithdrawalsRecord(wxMiniUserId, pageNo, pageSize);
    }

    /**
     * 审核通过
     *
     * @param id
     * @param remark
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pass(Long id, String remark, SysMember sysMember) {
        // 获取提现记录
        MallUserWithdrawalsRecord mallUserWithdrawalsRecord = mallUserWithdrawalsRecordDao.getById(id);
        Assert.notNull(mallUserWithdrawalsRecord, () -> new GlobalRunTimeException("提现记录不存在"));
        Assert.isTrue(WithdrawalsStatusEnum.TO_BE_WITHDRAWN == mallUserWithdrawalsRecord.getWithdrawalsStatus(), () -> new GlobalRunTimeException("提现状态异常"));
        //
        MallUserWallet mallUserWallet = mallUserWalletService.getMallUserWallet(mallUserWithdrawalsRecord.getMiniUserId());
        Assert.notNull(mallUserWallet, () -> new GlobalRunTimeException("用户钱包不存在"));
        // 提现成功 扣除锁定金额 加入总提现金额
        mallUserWalletService.addSumWithdraw(mallUserWallet, mallUserWithdrawalsRecord.getAmount());
        String outBatchNo = OrderNoUtil.getOrderNo("PC");
        // 修改提现记录状态
        mallUserWithdrawalsRecordDao.pass(id, sysMember.getId(), new Date(), remark, outBatchNo);
        WxMiniUserInfo wxMiniUserInfo = wxMiniUserInfoDao.getById(mallUserWithdrawalsRecord.getMiniUserId());
        Result<InitiateBatchTransferResponse> initiateBatchTransferResponseResult = wxMiniPayClient.batchTransfer(BatchTransferReq.buildOne(outBatchNo, remark, mallUserWithdrawalsRecord.getOutTradeNo(), mallUserWithdrawalsRecord.getAmount(),
                wxMiniUserInfo.getOpenId(), mallUserWithdrawalsRecord.getActualName()));
        if (initiateBatchTransferResponseResult.getCode() != 0 || !"ACCEPTED".equals(initiateBatchTransferResponseResult.getData().getBatchStatus())){
            throw new GlobalRunTimeException("提现失败");
        }
    }

    /**
     * 审核拒绝
     *
     * @param id
     * @param remark
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void turnDown(Long id, String remark, SysMember sysMember) {
        // 获取提现记录
        MallUserWithdrawalsRecord mallUserWithdrawalsRecord = mallUserWithdrawalsRecordDao.getById(id);
        Assert.notNull(mallUserWithdrawalsRecord, "提现记录不存在");
        Assert.isTrue(WithdrawalsStatusEnum.TO_BE_WITHDRAWN == mallUserWithdrawalsRecord.getWithdrawalsStatus(), "提现状态异常");
        //
        MallUserWallet mallUserWallet = mallUserWalletService.getMallUserWallet(mallUserWithdrawalsRecord.getMiniUserId());
        Assert.notNull(mallUserWallet, "用户钱包不存在");
        // 提现失败 将金额还原
        mallUserWalletService.subWithdrawingAmount(mallUserWallet, mallUserWithdrawalsRecord.getAmount(), MallUserWalletDetailTypeEnum.WITHDRAWAL_FAILED_TO_ADD);
        // 修改提现记录状态
        mallUserWithdrawalsRecordDao.turnDown(id, sysMember.getId(), new Date(), remark);
    }

}
